/***********************************************************
 *  File_Name  : XJRWLock.cpp
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : 线程读写锁
 *
 *  OS : Linux, UNIX, Windows
 *  LastVersion  : 20140820
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2014-8-20
 *  Version     : 20140820
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 ***********************************************************/
#include "XJRWLock.h"
#include <assert.h>

namespace XJUtilClass {


XJRWLock::XJRWLock()
: m_smRead			(MAXLONG)
, m_smWrite			(1)
, m_nWaitingReaders	(0)
, m_nWaitingWriters	(0)
, m_nActive			(0)
, m_dwWriterTID		(0)
, m_OK				(false)
{

}

XJRWLock::~XJRWLock()
{
	assert(m_nActive	 == 0);
	assert(m_dwWriterTID == 0);
}

void XJRWLock::WaitToRead()
{
	bool bWait = false;

	{
		XJMutexLocalLock locallock(m_cs);

		if(m_nActive > 0)
			++m_nActive;
		else if(m_nActive == 0)
		{
			if(m_nWaitingWriters == 0)
				++m_nActive;
			else
			{
				++m_nWaitingReaders;
				bWait = true;
			}
		}
		else
		{
			if(!IsOwner())
			{
				++m_nWaitingReaders;
				bWait = true;
			}
		}
	}

	if(bWait)
	{
		m_smRead.Wait();
	}
}

void XJRWLock::WaitToWrite()
{
	bool bWait = false;

	{
		XJMutexLocalLock locallock(m_cs);

		if(m_nActive > 0)
		{
			++m_nWaitingWriters;
			bWait = true;
		}
		else if(m_nActive == 0)
		{
			--m_nActive;
			SetOwner();
		}
		else
		{
			if(IsOwner())
				--m_nActive;
			else
			{
				++m_nWaitingWriters;
				bWait = true;
			}
		}
	}

	if(bWait)
	{
		m_smWrite.Wait();
		SetOwner();
	}
}

void XJRWLock::ReadDone()
{
	XJSemaphore* pSem	 = NULL;
	short  lCount = 0;

	{
		XJMutexLocalLock locallock(m_cs);

		assert(m_nActive != 0);

		if(m_nActive > 0)
		{
			if(--m_nActive == 0)
				Done(&pSem, lCount);
		}
		else
			assert(IsOwner());
	}

	if(pSem != NULL)
		pSem->Release(lCount);
}

void XJRWLock::WriteDone()
{
	XJSemaphore* pSem	 = NULL;
	short  lCount = 0;

	{
		XJMutexLocalLock locallock(m_cs);

		assert(m_nActive < 0);

		if(++m_nActive == 0)
		{
			DetachOwner();
			Done(&pSem, lCount);
		}
		else
			assert(IsOwner());
	}

	if(pSem != NULL)
		pSem->Release(lCount);
}

void XJRWLock::Done(XJSemaphore** ppSem, short& lCount)
{
	assert(m_nActive	 == 0);
	assert(m_dwWriterTID == 0);

	if(m_nWaitingWriters > 0)
	{
		--m_nActive;
		--m_nWaitingWriters;

		lCount = 1;
		*ppSem = &m_smWrite;
	}
	else if(m_nWaitingReaders > 0)
	{
		m_nActive			= m_nWaitingReaders;
		m_nWaitingReaders	= 0;
		lCount				= m_nActive;
		*ppSem				= &m_smRead;
	}
}


} /* namespace XJUtilClass */
